home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 2: Applications
/
Linux Cubed Series 2 - Applications.iso
/
circuits
/
pcb-1.000
/
pcb-1
/
pcb-1.3
/
crosshair.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-02-27
|
17KB
|
541 lines
/*
* COPYRIGHT
*
* PCB, interactive printed circuit board design
* Copyright (C) 1994,1995 Thomas Nau
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Contact addresses for paper mail and Email:
* Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
* Thomas.Nau@rz.uni-ulm.de
*
*/
static char *rcsid = "$Header: /sda4/users/nau/src/pcb/RCS/crosshair.c,v 2.1 1994/09/28 14:26:07 nau Exp nau $";
/* crosshair stuff
*/
#include <memory.h>
#include "global.h"
#include "crosshair.h"
#include "data.h"
#include "draw.h"
#include "error.h"
#include "mymem.h"
#include <X11/Xaw/Simple.h>
/* ---------------------------------------------------------------------------
* some local identifiers
*/
#define SAVE_STACK_DEPTH 20 /* deep enough for what we use it for */
static Boolean CrosshairStack[SAVE_STACK_DEPTH];
static int CrosshairStackPosition = 0;
static XPoint *PolygonPoints = NULL; /* data of tmp polygon */
static Cardinal MaxPoints = 0; /* number of points */
/* ---------------------------------------------------------------------------
* some local prototypes
*/
static void CreateTMPPolygon(PolygonTypePtr, Position, Position);
static void DrawCrosshair(void);
static void XORDrawElement(ElementTypePtr, Position, Position);
static void XORDrawBuffer(BufferTypePtr);
static void XORDrawMoveOrCopyObject(void);
static void DrawAttached(Boolean);
static void FitCrosshairIntoGrid(Position, Position);
/* ---------------------------------------------------------------------------
* creates a tmp polygon with coordinates converted to screen system
*/
static void CreateTMPPolygon(PolygonTypePtr Polygon, Position DX, Position DY)
{
/* allocate memory for data with screen coordinates */
if (Polygon->PointN >= MaxPoints)
{
/* allocate memory for one additional point */
MaxPoints = Polygon->PointN +1;
PolygonPoints = (XPoint *) MyRealloc(PolygonPoints,
MaxPoints *sizeof(XPoint), "CreateTMPPolygon()");
}
/* copy data to tmp array and convert it to screen coordinates */
POLYGONPOINT_LOOP(Polygon,
PolygonPoints[n].x = TO_SCREEN_X(point->X +DX);
PolygonPoints[n].y = TO_SCREEN_Y(point->Y +DY);
);
/* the last point is identical to the first one */
PolygonPoints[Polygon->PointN].x = PolygonPoints[0].x;
PolygonPoints[Polygon->PointN].y = PolygonPoints[0].y;
}
/* ---------------------------------------------------------------------------
* draws the crosshair
* don't transform MAX_COORD to screen coordinats, it is
* already the maximum of screen- and pcb-coordinates
*/
static void DrawCrosshair(void)
{
XDrawLine(Dpy, Output.OutputWindow, Crosshair.GC,
TO_SCREEN_X(Crosshair.X), 0, TO_SCREEN_X(Crosshair.X), MAX_COORD);
XDrawLine(Dpy, Output.OutputWindow, Crosshair.GC,
0, TO_SCREEN_Y(Crosshair.Y), MAX_COORD, TO_SCREEN_Y(Crosshair.Y));
}
/* ---------------------------------------------------------------------------
* draws the elements of a loaded circuit which is to be merged in
*/
static void XORDrawElement(ElementTypePtr Element, Position DX, Position DY)
{
ELEMENTLINE_LOOP(Element,
XDrawLine(Dpy, Output.OutputWindow, Crosshair.AttachGC,
TO_SCREEN_X(DX +line->X1), TO_SCREEN_Y(DY +line->Y1),
TO_SCREEN_X(DX +line->X2), TO_SCREEN_Y(DY +line->Y2));
);
/* arc coordinates and angles have to be converted to X11 notation */
ARC_LOOP(Element,
XDrawArc(Dpy, Output.OutputWindow, Crosshair.AttachGC,
TO_SCREEN_X(DX +arc->X -arc->Width),
TO_SCREEN_Y(DY +arc->Y -arc->Height),
TO_SCREEN(2*arc->Width), TO_SCREEN(2*arc->Height),
(arc->StartAngle +180) *64, arc->Delta *64);
);
/* pin coordinates and angles have to be converted to X11 notation */
PIN_LOOP(Element,
XDrawArc(Dpy, Output.OutputWindow, Crosshair.AttachGC,
TO_SCREEN_X(DX +pin->X -pin->Thickness/2),
TO_SCREEN_Y(DY +pin->Y -pin->Thickness/2),
TO_SCREEN(pin->Thickness), TO_SCREEN(pin->Thickness),
0, 360*64);
);
}
/* ---------------------------------------------------------------------------
* draws all visible and attached objects of the pastebuffer
*/
static void XORDrawBuffer(BufferTypePtr Buffer)
{
Cardinal i;
Position x, y;
/* set offset */
x = Crosshair.X -Buffer->X;
y = Crosshair.Y -Buffer->Y;
/* draw all visible layers */
for (i = 0; i < MAX_LAYER; i++)
if (PCB->Data->Layer[i].On)
{
LayerTypePtr layer = &Buffer->Data->Layer[i];
LINE_LOOP(layer,
XDrawLine(Dpy, Output.OutputWindow, Crosshair.AttachGC,
TO_SCREEN_X(x +line->X1), TO_SCREEN_Y(y +line->Y1),
TO_SCREEN_X(x +line->X2), TO_SCREEN_Y(y +line->Y2));
);
TEXT_LOOP(layer,
{
BoxTypePtr box = &text->BoundingBox;
XDrawRectangle(Dpy, Output.OutputWindow, Crosshair.AttachGC,
TO_SCREEN_X(x +box->X1), TO_SCREEN_Y(y +box->Y1),
TO_SCREEN(box->X2 -box->X1),
TO_SCREEN(box->Y2 -box->Y1));
}
);
/* the tmp polygon has n+1 points because the first
* and the last one are set to the same coordinates
*/
POLYGON_LOOP(layer,
{
CreateTMPPolygon(polygon, x, y);
XDrawLines(Dpy, Output.OutputWindow, Crosshair.AttachGC,
PolygonPoints, polygon->PointN+1, CoordModeOrigin);
}
);
}
/* draw elements if visible */
if (PCB->PinOn || PCB->ElementOn)
ELEMENT_LOOP(Buffer->Data, XORDrawElement(element, x, y););
/* and the vias, move offset by thickness/2 */
if (PCB->ViaOn)
VIA_LOOP(Buffer->Data,
XDrawArc(Dpy, Output.OutputWindow, Crosshair.AttachGC,
TO_SCREEN_X(x +via->X -via->Thickness/2),
TO_SCREEN_Y(y +via->Y -via->Thickness/2),
TO_SCREEN(via->Thickness), TO_SCREEN(via->Thickness),
0, 360*64);
);
}
/* ---------------------------------------------------------------------------
* draws the attched object while in MOVE_MODE or COPY_MODE
*/
static void XORDrawMoveOrCopyObject(void)
{
Position dx = Crosshair.X -Crosshair.AttachedObject.X,
dy = Crosshair.Y -Crosshair.AttachedObject.Y;
switch(Crosshair.AttachedObject.Type)
{
case VIA_TYPE:
{
PinTypePtr via = (PinTypePtr) Crosshair.AttachedObject.Ptr2;
XDrawArc(Dpy, Output.OutputWindow, Crosshair.AttachGC,
TO_SCREEN_X(Crosshair.X -via->Thickness/2),
TO_SCREEN_Y(Crosshair.Y -via->Thickness/2),
TO_SCREEN(via->Thickness), TO_SCREEN(via->Thickness),0,360*64);
break;
}
case LINE_TYPE:
{
LineTypePtr line = (LineTypePtr) Crosshair.AttachedObject.Ptr2;
XDrawLine(Dpy, Output.OutputWindow, Crosshair.AttachGC,
TO_SCREEN_X(line->X1 +dx), TO_SCREEN_Y(line->Y1 +dy),
TO_SCREEN_X(line->X2 +dx), TO_SCREEN_Y(line->Y2 +dy));
break;
}
case POLYGON_TYPE:
{
PolygonTypePtr polygon = (PolygonTypePtr) Crosshair.AttachedObject.Ptr2;
/* the tmp polygon has n+1 points because the first
* and the last one are set to the same coordinates
*/
CreateTMPPolygon(polygon, dx, dy);
XDrawLines(Dpy, Output.OutputWindow, Crosshair.AttachGC,
PolygonPoints, polygon->PointN +1, CoordModeOrigin);
break;
}
case POLYGONPOINT_TYPE:
{
PolygonTypePtr polygon;
PolygonPointTypePtr point,
previous,
following;
polygon = (PolygonTypePtr) Crosshair.AttachedObject.Ptr1;
point = (PolygonPointTypePtr) Crosshair.AttachedObject.Ptr2;
/* get previous and following point */
if (point == polygon->Points)
{
previous = &polygon->Points[polygon->PointN-1];
following = point+1;
}
else
if (point == &polygon->Points[polygon->PointN-1])
{
previous = point-1;
following = &polygon->Points[0];
}
else
{
previous = point-1;
following = point+1;
}
/* draw the two segments */
XDrawLine(Dpy, Output.OutputWindow, Crosshair.AttachGC,
TO_SCREEN_X(previous->X), TO_SCREEN_Y(previous->Y),
TO_SCREEN_X(point->X +dx), TO_SCREEN_Y(point->Y +dy));
XDrawLine(Dpy, Output.OutputWindow, Crosshair.AttachGC,
TO_SCREEN_X(point->X +dx), TO_SCREEN_Y(point->Y +dy),
TO_SCREEN_X(following->X), TO_SCREEN_Y(following->Y));
break;
}
/* element names are moved like normal text objects */
case TEXT_TYPE:
case ELEMENTNAME_TYPE:
{
BoxTypePtr box;
box = &((TextTypePtr) Crosshair.AttachedObject.Ptr2)->BoundingBox;
XDrawRectangle(Dpy, Output.OutputWindow, Crosshair.AttachGC,
TO_SCREEN_X(box->X1 +dx), TO_SCREEN_Y(box->Y1 +dy),
TO_SCREEN(box->X2 -box->X1), TO_SCREEN(box->Y2 -box->Y1));
break;
}
/* pin movements result in moving an element */
case PIN_TYPE:
case ELEMENT_TYPE:
XORDrawElement((ElementTypePtr) Crosshair.AttachedObject.Ptr2,
dx, dy);
break;
}
}
/* ---------------------------------------------------------------------------
* draws additional stuff that follows the crosshair
*/
static void DrawAttached(Boolean BlockToo)
{
DrawCrosshair();
switch (Settings.Mode)
{
case VIA_MODE:
XDrawArc(Dpy, Output.OutputWindow, Crosshair.AttachGC,
TO_SCREEN_X(Crosshair.X -Settings.ViaThickness/2),
TO_SCREEN_Y(Crosshair.Y -Settings.ViaThickness/2),
TO_SCREEN(Settings.ViaThickness),
TO_SCREEN(Settings.ViaThickness),
0, 360*64);
break;
/* the attached line is used by both LINEMODE and POLYGON_MODE */
case LINE_MODE:
case POLYGON_MODE:
/* draw only if starting point is set */
if (Crosshair.AttachedLine.State != STATE_FIRST)
XDrawLine(Dpy, Output.OutputWindow, Crosshair.AttachGC,
TO_SCREEN_X(Crosshair.AttachedLine.X1),
TO_SCREEN_Y(Crosshair.AttachedLine.Y1),
TO_SCREEN_X(Crosshair.AttachedLine.X2),
TO_SCREEN_Y(Crosshair.AttachedLine.Y2));
/* draw attached polygon only if in POLYGON_MODE */
if (Settings.Mode == POLYGON_MODE &&
Crosshair.AttachedPolygon.PointN > 1)
{
CreateTMPPolygon(&Crosshair.AttachedPolygon, 0, 0);
XDrawLines(Dpy, Output.OutputWindow, Crosshair.AttachGC,
PolygonPoints, Crosshair.AttachedPolygon.PointN,
CoordModeOrigin);
}
break;
case PASTEBUFFER_MODE:
XORDrawBuffer(PASTEBUFFER);
break;
case COPY_MODE:
case MOVE_MODE:
XORDrawMoveOrCopyObject();
break;
}
/* an attached box does not depend on a special mode */
if (Crosshair.AttachedBox.State == STATE_SECOND ||
(BlockToo && Crosshair.AttachedBox.State == STATE_THIRD))
{
Position x1, y1, /* upper left corner */
x2, y2; /* lower right corner */
x1 = MIN(Crosshair.AttachedBox.X1, Crosshair.AttachedBox.X2);
y1 = MIN(Crosshair.AttachedBox.Y1, Crosshair.AttachedBox.Y2);
x2 = MAX(Crosshair.AttachedBox.X1, Crosshair.AttachedBox.X2);
y2 = MAX(Crosshair.AttachedBox.Y1, Crosshair.AttachedBox.Y2);
XDrawRectangle(Dpy, Output.OutputWindow, Crosshair.AttachGC,
TO_SCREEN_X(x1), TO_SCREEN_Y(y1),
TO_SCREEN(x2-x1), TO_SCREEN(y2-y1));
}
}
/* ---------------------------------------------------------------------------
* switches crosshair on
*/
void CrosshairOn(Boolean BlockToo)
{
if (!Crosshair.On)
{
Crosshair.On = True;
DrawAttached(BlockToo);
}
}
/* ---------------------------------------------------------------------------
* switches crosshair off
*/
void CrosshairOff(Boolean BlockToo)
{
if (Crosshair.On)
{
Crosshair.On = False;
DrawAttached(BlockToo);
}
}
/* ---------------------------------------------------------------------------
* saves crosshair state (on/off) and hides him
*/
void HideCrosshair(Boolean BlockToo)
{
CrosshairStack[CrosshairStackPosition++] = Crosshair.On;
if (CrosshairStackPosition >= SAVE_STACK_DEPTH)
CrosshairStackPosition--;
CrosshairOff(BlockToo);
}
/* ---------------------------------------------------------------------------
* restores last crosshair state
*/
void RestoreCrosshair(Boolean BlockToo)
{
if (CrosshairStackPosition)
{
if (CrosshairStack[--CrosshairStackPosition])
CrosshairOn(BlockToo);
else
CrosshairOff(BlockToo);
}
}
/* ---------------------------------------------------------------------------
* recalculates the passed coordinates to fit the current grid setting
*/
static void FitCrosshairIntoGrid(Position X, Position Y)
{
Position x1, y1, x2, y2;
/* get PCB coordinates from visible display size */
x1 = TO_PCB_X(Output.OffsetX);
y1 = TO_PCB_Y(Output.OffsetY);
x2 = TO_PCB_X(Output.OffsetX +Output.Width -1);
y2 = TO_PCB_Y(Output.OffsetY +Output.Height -1);
/* check position agains window size and agains valid
* coordinates determined by the size of an attached
* object or buffer
*/
Crosshair.X = (X < x1 || X > x2) ? Crosshair.X : X;
Crosshair.Y = (Y < y1 || Y > y2) ? Crosshair.Y : Y;
Crosshair.X = MIN(Crosshair.MaxX, MAX(Crosshair.MinX, Crosshair.X));
Crosshair.Y = MIN(Crosshair.MaxY, MAX(Crosshair.MinY, Crosshair.Y));
/* check if new position is inside the output window
* This might not be true after the window has been resized.
* In this case we just set it to the center of the window or
* with respect to the grid (if possible)
*/
if (Crosshair.X < x1 || Crosshair.X > x2)
{
if (x2 -x1 +1 >= PCB->Grid)
/* there must be a point that matches the grid
* so we just have to look for it with some integer
* calculations
*/
Crosshair.X = GRIDFIT_X(x1 +PCB->Grid);
else
Crosshair.X = (x1+x2)/2;
}
else
/* check if the new position matches the grid */
Crosshair.X = GRIDFIT_X(Crosshair.X);
/* to the same for the second coordinate */
if (Crosshair.Y < y1 || Crosshair.Y > y2)
{
if (y2 -y1 +1 >= PCB->Grid)
Crosshair.Y = GRIDFIT_Y(y1 +PCB->Grid);
else
Crosshair.Y = (y1+y2)/2;
}
else
Crosshair.Y = GRIDFIT_Y(Crosshair.Y);
}
/* ---------------------------------------------------------------------------
* move crosshair relative (has to be switched off)
*/
void MoveCrosshairRelative(Position DeltaX, Position DeltaY)
{
FitCrosshairIntoGrid(Crosshair.X +DeltaX, Crosshair.Y +DeltaY);
}
/* ---------------------------------------------------------------------------
* move crosshair absolute (has to be switched off)
*/
void MoveCrosshairAbsolute(Position X, Position Y)
{
FitCrosshairIntoGrid(X, Y);
}
/* ---------------------------------------------------------------------------
* sets the valid range for the crosshair cursor
*/
void SetCrosshairRange(Position MinX, Position MinY,
Position MaxX, Position MaxY)
{
Crosshair.MinX = MAX(0, MinX);
Crosshair.MinY = MAX(0, MinY);
Crosshair.MaxX = MIN((Position) PCB->MaxWidth, MaxX);
Crosshair.MaxY = MIN((Position) PCB->MaxHeight, MaxY);
/* force update of position */
MoveCrosshairRelative(0, 0);
}
/* ---------------------------------------------------------------------------
* initializes crosshair stuff
* clears the struct, allocates to graphical contexts and
* initializes the stack
*/
void InitCrosshair(void)
{
/* clear struct */
memset(&Crosshair, 0, sizeof(CrosshairType));
Crosshair.GC = XCreateGC(Dpy, Output.OutputWindow, 0, NULL);
Crosshair.AttachGC = XCreateGC(Dpy, Output.OutputWindow, 0, NULL);
if (!VALID_GC((int) Crosshair.GC) || !VALID_GC((int) Crosshair.AttachGC))
MyFatal("can't create default crosshair GC\n");
XSetState(Dpy, Crosshair.GC, Settings.CrosshairColor, Settings.bgColor,
GXxor, AllPlanes);
/* change to invert mode for drawing buffer contents */
XCopyGC(Dpy, Crosshair.GC, -1, Crosshair.AttachGC);
XSetState(Dpy, Crosshair.AttachGC, Settings.bgColor,
Settings.CrosshairColor, GXinvert, AllPlanes);
/* fake an crosshair off entry on stack */
CrosshairStackPosition = 0;
CrosshairStack[CrosshairStackPosition++] = True;
Crosshair.On = False;
/* set default limits */
Crosshair.MinX = Crosshair.MinY = 0;
Crosshair.MaxX = PCB->MaxWidth;
Crosshair.MaxY = PCB->MaxHeight;
}
/* ---------------------------------------------------------------------------
* exits crosshair routines, release GCs
*/
void DestroyCrosshair(void)
{
CrosshairOff(True);
FreePolygonMemory(&Crosshair.AttachedPolygon);
XFreeGC(Dpy, Crosshair.GC);
XFreeGC(Dpy, Crosshair.AttachGC);
}